<?php
/**
 * @author dinglin
 * 打卡机故障问题，没有打卡记录，且在AdjustYesterdayStatus跑过之后处理
 * 公出和请假的打卡异常状况，上一个job已经处理
 * 次job只处理打卡正常，状态不正常情况
 * */
apf_require_class('Oa_Job_Attendance_Abstract');
apf_require_class('Const_LeaveType');
apf_require_class('Tools_Tools');
class Oa_Job_Attendance_DoErrorRecordStatus extends Oa_Job_Attendance_Abstract {

    /** 考勤系统读 **/
    private $readdb = "attendance_slave";
    /** 考勤系统写 **/
    private $writedb = "attendance_master";

    private $date = '';
    private $startwork = 910;
    private $endwork = 1800;
    private $chidao = 930;
    private $pmstart = 1400;
    private $zaotui = 1730;
    private $sp_endwork =0;//特殊下班的时间点
    private $sp_startwork =0;//特殊上班时间点
    public function run($params = 0){
        //初始化需要校正的日期,如无指定，取上一天
        if ($params) {
            $this->date = intval(date('Ymd',strtotime($params)));
        }else{
            return;
        }
        $this->log("开始准备校正数据...");
        //特殊下班时间
        $special_leave_time = Tools_Tools::get_instance()->special_leave_time();
        $yesterday = date('Y-m-d',strtotime($this->date));
        if(isset($special_leave_time[$yesterday])){
            $sp_endtime = intval(date('Hi',strtotime($special_leave_time[$yesterday]['leave_time'])));
            $sp_starttime = intval(date('Hi',strtotime($special_leave_time[$yesterday]['start_time'])));
            if($sp_starttime > $this->startwork){
                $this->sp_startwork = $sp_starttime;
            }
            if($sp_endtime < $this->endwork){
                $this->sp_endwork = $sp_endtime;
            }
        }
        $last_timetamp = strtotime($this->date);
        //第一步：获取所有需打卡在职员工信息，（提醒初始化数据时，是否为正常上班工作日）
        $userinfo =  $this->get_all_user_info($last_timetamp);
        if (empty($userinfo)) {
            $this->log("用户信息获取失败!");
            die();
        }

        //第二步：需要处理了的数据进行处理
        $this->deal_unnormal_data($userinfo);
        $this->log("数据校正完毕");
    }

    /**
     * 对存在的异常数据进行处理
     * @param array() $data
     * @return void
     * **/
    private function deal_unnormal_data($userinfo) {
        if (empty($userinfo)) {
            return;
        }
        $this->log("开始处理打卡正常数据......");
        //数据处理，遍历数据
        foreach ($userinfo as $key => $user) {
            //第一步:获取每个人对应的打卡记录 全天打卡正常，直接校正
            $record = $this->get_user_access_day_record($user['user_id']);//每日打卡时间
            if(empty($record)){
                //全天缺勤，不需处理
                continue;
            }elseif( ($record['start_work'] <= $this->startwork || $record['start_work'] <= $this->sp_startwork) && ($record['end_work'] >= $this->endwork || ($this->sp_endwork && $record['end_work'] >= $this->sp_endwork))){
                //全天正常，需要校正
                $data['am_status'] = Const_LeaveType::KQ_AM_STATUS_5;
                $data['pm_status'] = Const_LeaveType::KQ_PM_STATUS_6;
                $data['days'] = 0;
                $this->change_user_status($data,$user['user_id']);
                continue;
            }
            //第二步：上午或下午异常校正
            $cuser = $this->get_special_day_status($user['user_id']);//每日最终状态
            //全天请假，且批准 ，不需校正
            if($cuser['am_type'] && $cuser['pm_type'] && $cuser['am_leave_status']==Const_LeaveType::LEAVE_STATUS_PASS && $cuser['pm_leave_status']==Const_LeaveType::LEAVE_STATUS_PASS){
                continue;
            }
            $guser = $this->get_leave_gongchu($user['user_id']);//公出
            //判断是否有公出
            $is_normal_am = false;
            $is_normal_pm = false;
            if($guser) {
                //取所有公出校正数据,其中一条满足即退出
                foreach ($guser as $k => $v) {
                    $gstart = intval(date('Hi',strtotime($v['start_time'])));
                    $gend = intval(date('Hi',strtotime($v['end_time'])));
                    //当天有打卡记录的
                    if($record['end_work'] && $record['start_work']) {
                        //上午能覆盖
                        if ($gstart <= $this->startwork && $gend >= $record['start_work']) {
                            $is_normal_am = true;
                        }elseif($this->sp_startwork && $gstart <= $this->sp_startwork && $gend >= $record['start_work']){
                            $is_normal_am = true;
                        }
                        //下午能覆盖
                         if ($gstart <= $record['end_work'] && $gend >= $this->endwork) {
                             $is_normal_pm = true;
                         }elseif($this->sp_endwork && $gstart <= $record['end_work'] && $gend >= $this->sp_endwork){
                             $is_normal_pm = true;
                         }
                    } else {//无打卡记录，
                        //上午覆盖
                        if ($gstart <= $this->startwork && $gend >= 1200) {
                            $is_normal_am = true;
                        }elseif($this->sp_startwork && $gstart <= $this->sp_startwork && $gend >= 1200){
                            $is_normal_am = true;
                        }
                        //下午覆盖
                        if ($gstart <= 1400 && $gend >= $this->endwork) {
                            $is_normal_pm = true;
                        }elseif($this->sp_endwork && $gend >= $this->sp_endwork && $gstart <= 1400){
                            $is_normal_pm = true;
                        }
                    }
                }
            }
            //特殊班别
            $user_type = $user['user_type'];
            $user_type_date = intval($user['user_type_date']);
            $data = array();
            if($user_type && $user_type_date && $user_type_date <= $this->date){//特殊班别
                //特殊班别,全天缺勤，没有公出，且没有请假，出差
                //有请假，未批准
                if((!$record['start_work'] && !$record['end_work'] && !$guser && !$cuser['am_type'] && !$cuser['pm_type'])||( $cuser['am_type'] && $cuser['am_leave_status']== Const_LeaveType::LEAVE_STATUS_AUDIT ) ||($cuser['pm_type'] && $cuser['am_leave_status']== Const_LeaveType::LEAVE_STATUS_AUDIT)){
                    $data['am_status'] = Const_LeaveType::KQ_AM_STATUS_3;
                    $data['pm_status'] = Const_LeaveType::KQ_PM_STATUS_4;
                    $data['is_later'] = 0;
                    $data['leave_early'] =0;
                    $data['days'] = 1;
                }else{//之上至少一次
                    $data['am_status'] = Const_LeaveType::KQ_AM_STATUS_5;
                    $data['is_later'] = 0;
                    $data['pm_status'] = Const_LeaveType::KQ_PM_STATUS_6;
                    $data['leave_early'] =0;
                    $data['days'] = 0;
                }
            }else{//非特殊班别

                  //上午异常
                if(!$cuser['am_type'] || ( $cuser['am_type'] && $cuser['am_leave_status']!= Const_LeaveType::LEAVE_STATUS_PASS )){//没有请假，或请假未批准
                    if(!$is_normal_am) {//公出没有覆盖
                        if($this->sp_startwork && (!$record['start_work'] || $record['start_work'] > $this->sp_startwork)){//上午缺勤
                            //缺勤不需处理
                        }elseif(!$this->sp_startwork && (!$record['start_work'] ||  $record['start_work'] > $this->chidao)){//上午缺勤
                            //缺勤不需处理
                        }elseif(!$this->sp_startwork && $record['start_work'] && $record['start_work'] > $this->startwork){//迟到
                            $data['am_status'] = Const_LeaveType::KQ_AM_STATUS_1;
                            $data['is_later'] = 1;
                            $data['days'] = $cuser['days'] - 0.5;
                            $cuser['days'] -= 0.5;
                        }elseif($this->sp_startwork && $record['start_work'] && $record['start_work'] <= $this->sp_startwork){//正常
                            $data['am_status'] = Const_LeaveType::KQ_AM_STATUS_5;
                            $data['days'] = $cuser['days'] - 0.5;
                            $cuser['days'] -= 0.5;
                        }elseif(!$this->sp_startwork && $record['start_work'] && $record['start_work'] <= $this->startwork){//正常
                            $data['am_status'] = Const_LeaveType::KQ_AM_STATUS_5;
                            $data['days'] = $cuser['days'] - 0.5;
                            $cuser['days'] -= 0.5;
                        }
                    }
                }
                  //下午异常
                if(!$cuser['pm_type'] || ( $cuser['pm_type'] && $cuser['pm_leave_status']!= Const_LeaveType::LEAVE_STATUS_PASS )){//没有请假，或请假未批准
                    if(!$is_normal_pm){//公出没有覆盖
                        if($this->sp_endwork && (!$record['end_work'] || $record['end_work'] < $this->sp_endwork)){//下午缺勤
                            //缺勤不需处理
                        }elseif(!$this->sp_endwork && (!$record['end_work'] ||  $record['end_work'] < $this->zaotui)){//下午缺勤
                            //缺勤不需处理
                        }elseif(!$this->sp_endwork && $record['end_work'] && $record['end_work'] < $this->endwork){//早退
                            $data['pm_status'] = Const_LeaveType::KQ_PM_STATUS_2;
                            $data['leave_early'] = 1;
                            $data['days'] = $cuser['days'] - 0.5;
                        }elseif($this->sp_endwork && $record['end_work'] && $record['end_work'] >= $this->sp_endwork){//正常
                            $data['pm_status'] = Const_LeaveType::KQ_PM_STATUS_6;
                            $data['days'] = $cuser['days'] - 0.5;
                        }
                        elseif(!$this->sp_endwork && $record['end_work'] && $record['end_work'] >= $this->endwork){//正常
                            $data['pm_status'] = Const_LeaveType::KQ_PM_STATUS_6;
                            $data['days'] = $cuser['days'] - 0.5;
                        }
                    }
                }
            }
            if(!empty($data)){
                if($data['days'] <0 ){
                    $data['days'] = 0;
                }
                $this->change_user_status($data,$user['user_id']);
            }
        }
        unset($datalist);
    }
    /**
     * 调整处理最终状态
     * @param array $data
     * **/
    private function change_user_status($data,$uid) {
        if (empty($data) || empty($uid)) {
            return;
        }
        $value = '';
        foreach ($data as $key => $val) {
            $value .= $key." = '{$val}',";
        }
        $value = substr($value,0,-1);
        $sql = "UPDATE user_day_status SET $value WHERE user_id = {$uid} AND dateline = {$this->date}";
        $this->execute($sql,array(),$this->writedb);
    }

    /**
     * 取出指定时间的最终打卡记录
     * @param array() $uids
     * @return array
     * **/
    private function get_special_day_status($uid) {
        $sql = "SELECT * FROM user_day_status WHERE user_id ={$uid} AND dateline = {$this->date}";
        return $this->get_db_row($sql,$this->writedb,array());
    }

    /**
     * 获取公出的记录
     * TO DO 提醒冗余公出时间点
     * @param array() $uids
     * @return array 用户可能对应多条数据
     * **/
    private function get_leave_gongchu($uid) {
        $result = array();
        //取出公出的记录
        $gtype = Const_LeaveType::LEAVE_TYPE_GONGCHU;
        $sql = "SELECT * FROM user_leave_daily WHERE leave_type = {$gtype} AND user_id={$uid} AND dateline = {$this->date}";
        $tmp = $this->get_db_rows($sql,$this->writedb,array());
        if(empty($tmp)) {
            return $result;
        }
        //取出公出详细时间
        $lids =  array();
        foreach ($tmp as $key => $val) {
            $lids[] = $val['leave_id'];
        }
        $lids = implode(',',$lids);
        $lsql = "SELECT id,user_id,start_time,end_time FROM leave_record WHERE id in ({$lids})";
        return $this->get_db_rows($lsql,$this->writedb,array());
    }

    /**
     * 获取所有在职员工信息
     * @params int $last_timetamp
     * @return array()
     * **/
    private function get_all_user_info($last_timetamp) {
        $result = array();
        if (empty($last_timetamp)) {
            return $result;
        }
        $city_card = APF::get_instance()->get_config('city_card');
        $city_names = array_values($city_card);
        $city = " AND city_name IN('".implode("','", $city_names)."')";
        $lastday = date('Y-m-d',$last_timetamp)." 00:00:00";
        $start = 0;
        $limit = 100;
        while(true) {
            $sql = "SELECT user_id,user_type,user_type_date,enter_date,department_id FROM user_info WHERE user_id > {$start} AND (dimission_date = '0000-00-00 00:00:00' OR dimission_date >= '{$lastday}') {$city} ORDER BY user_id asc limit {$limit}";
            $tmp = $this->get_db_rows($sql,$this->writedb,array());
            if(empty($tmp)) {
                $this->log("取完所有用户数据!");
                break;
            }
            $count = count($tmp);
            $start = $tmp[$count - 1]['user_id'];
            $result = array_merge($result,$tmp);
        }
        //过滤未入职员工
        foreach ($result as $index => $value){
            $enter_time = strtotime($value['enter_date']);
            if($enter_time >= $last_timetamp){
                unset($result[$index]);
            }
            if(!empty($sale_department[$value['department_id']])){
                unset($result[$index]);
                continue;
            }
        }
        return $result;
    }

    /**
     *根据用户id,获取打卡记录
     *@params array $uids
     *@return array
     * **/
    private function get_user_access_day_record($uid) {
        $sql = "SELECT user_id,start_work,end_work FROM access_day_record WHERE user_id = {$uid} AND access_date = {$this->date}";
        return $this->get_db_row($sql,$this->writedb,array());
    }

}
